/*AlphaGradientPanel, an extended panel
  By Nick Waelti
  http://www.codeproject.com/KB/cpp/AlphaGradientPanel.aspx
  Converted to C# by me.*/

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Jonathan.AlphaGradientPanel
{
    public class AlphaGradientPanel : Control
    {
        public AlphaGradientPanel ()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
			this.SetStyle(ControlStyles.UserPaint, true);

			this.BackColor = Color.Transparent;
			this.Paint += new PaintEventHandler(AlphaGradientPanel_Paint);
			clGradient = new ColorWithAlphaCollection(this);
        }

        #region "PROPERTIES"
        private bool bRoundCorners = true;
        [Category("Borders")]
        public bool Rounded
        {
            get { return bRoundCorners; }
            set
            {
                bRoundCorners = value;
                Invalidate();
            }
        }

        private Corner eCorners = Corner.All;
        [Category("Borders")]
        public Corner Corners
        {
            get { return eCorners; }
            set
            {
                eCorners = value;
                Invalidate();
            }
        }

        private Color clBorder = SystemColors.ActiveBorder;
        [Category("Borders")]
        public Color BorderColor
        {
            get { return clBorder; }
            set
            {
                clBorder = value;
                Invalidate();
            }
        }

        private bool bGradient = true;
        [Category("Content")]
        public bool Gradient
        {
            get { return bGradient; }
            set
            {
                bGradient = value;
                Invalidate();
            }
        }

        private bool bBorder = true;
        [Category("Borders")]
        public bool Border
        {
            get { return bBorder; }
            set
            {
                bBorder = value;
                Invalidate();
            }
        }

        private int iCornerRadius = 20;
        [Category("Borders")]
        public int CornerRadius
        {
            get { return iCornerRadius; }
            set
            {
                iCornerRadius = value;
                Invalidate();
            }
        }

        private LinearGradientMode gmMode = LinearGradientMode.Vertical;
        [Category("Content")]
        public LinearGradientMode GradientMode
        {
            get { return gmMode; }
            set
            {
                gmMode = value;
                Invalidate();
            }
        }

        private Image imImage;
        [Category("Image")]
        public Image Image
        {
            get { return imImage; }
            set
            {
                imImage = value;
                Invalidate();
            }
        }

        private ImagePosition eImagePosition = ImagePosition.BottomRight;
        [Category("Image")]
        public ImagePosition ImagePosition
        {
            get { return eImagePosition; }
            set
            {
                eImagePosition = value;
                Invalidate();
            }
        }

        private Size szImageSize = new Size(48, 48);
        [Category("Image")]
        public Size ImageSize
        {
            get { return szImageSize; }
            set
            {
                szImageSize = value;
                Invalidate();
            }
        }

        private int iImageAlpha = 75;
        [Category("Image")]
        public int ImageAlpha
        {
            get { return iImageAlpha; }
            set
            {
                iImageAlpha = value;
                Invalidate();
            }
        }

        private Padding pdImage = new Padding(5);
        [Category("Image")]
        public Padding ImagePadding
        {
            get { return pdImage; }
            set
            {
                pdImage = value;
                Invalidate();
            }
        }

        private Padding pdContent = new Padding(0);
        [Category("Content")]
        public Padding ContentPadding
        {
            get { return pdContent; }
            set
            {
                pdContent = value;
                Invalidate();
            }
        }

        private bool bGrayscale = false;
        [Category("Image")]
        public bool Grayscale
        {
            get { return bGrayscale; }
            set
            {
                bGrayscale = value;
                Invalidate();
            }
        }

        private Size szGradient;
        [Category("Content")]
        public Size GradientSize
        {
            get { return szGradient; }
            set
            {
                szGradient = value;
                Invalidate();
            }
        }

        private WrapMode wmWrap = WrapMode.Tile;
        [Category("Content")]
        public WrapMode GradientWrapMode
        {
            get { return wmWrap; }
            set
            {
                wmWrap = value;
                Invalidate();
            }
        }

        private float snOffset = 1;
        [Category("Content")]
        public float GradientOffset
        {
            get { return snOffset; }
            set
            {
                snOffset = value;
                Invalidate();
            }
        }

        private ContentAlignment m_TextAlign = ContentAlignment.TopLeft;
        [Category("Content")]
        public ContentAlignment TextAlign
        {
            get { return m_TextAlign; }
            set
            {
                m_TextAlign = value;
                Invalidate();
            }
        }

        private ColorWithAlphaCollection clGradient;// = new ColorWithAlphaCollection(this);
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Category("Content")]
        public ColorWithAlphaCollection Colors
        {
            get { return clGradient; }
        }

        #endregion

        #region "EVENTS"
        protected override void OnFontChanged (System.EventArgs e)
        {
            base.OnFontChanged(e);
            this.Invalidate();
        }

        protected override void OnPaddingChanged (System.EventArgs e)
        {
            base.OnPaddingChanged(e);
            this.Invalidate();
        }
        #endregion

        void AlphaGradientPanel_Paint (object sender, PaintEventArgs e)
        {
            Brush brBrush;
            Rectangle rcClient = new Rectangle(ContentPadding.Left, ContentPadding.Top, this.Width - ContentPadding.Right - ContentPadding.Left, this.Height - ContentPadding.Bottom - ContentPadding.Top);

            if (Gradient)
            {
                Rectangle rcBrush;
                if (!szGradient.IsEmpty)
                {
                    rcBrush = new Rectangle(0, 0, GradientSize.Width, GradientSize.Height);
                }
                else
                {
                    rcBrush = rcClient;
                }

                if (Colors.Count > 1)
                {
                    brBrush = new LinearGradientBrush(rcBrush, Color.White, Color.White, GradientMode);
                    {
                        if (GradientWrapMode == WrapMode.Clamp)
                            GradientWrapMode = WrapMode.Tile;
                        ((LinearGradientBrush)brBrush).WrapMode = GradientWrapMode;
                        ((LinearGradientBrush)brBrush).SetSigmaBellShape(snOffset);
                        ColorBlend cb = new ColorBlend(Colors.Count);
                        for (int i = 0; i <= Colors.Count - 1; i++)
                        {
                            cb.Positions[i] = (1f / (cb.Positions.Length - 1)) * i;
                            cb.Colors[i] = Color.FromArgb(Colors[i].Alpha, Colors[i].Color.R, Colors[i].Color.G, Colors[i].Color.B);
                        }
                        ((LinearGradientBrush)brBrush).InterpolationColors = cb;
                    }
                }
                else
                {
                    brBrush = new SolidBrush(Color.Transparent);
                    e.Graphics.DrawString("[GRADIENT] Not enough color (at least 2 needed)", SystemFonts.DialogFont, Brushes.Black, 5, 5);
                }
            }
            else
            {
                if (Colors.Count > 0)
                {
                    ColorWithAlpha cwa = (ColorWithAlpha)Colors[0];
                    brBrush = new SolidBrush(Color.FromArgb(cwa.Alpha, cwa.Color.R, cwa.Color.G, cwa.Color.B));
                }
                else
                {
                    brBrush = new SolidBrush(Color.Transparent);
                    e.Graphics.DrawString("[SOLID] Not enough color (at least 1 needed)", SystemFonts.DialogFont, Brushes.Black, 5, 5);
                }

            }

            e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            e.Graphics.CompositingMode = CompositingMode.SourceOver;
            e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            Rectangle rcBorder = new Rectangle(rcClient.X, rcClient.Y, rcClient.Width - 1, rcClient.Height - 1);
            Rectangle rcContent = rcClient;

            if (Rounded)
            {
                e.Graphics.FillPath(brBrush, DrawingHelper.RoundedRect(rcContent, iCornerRadius, Corners));
                if (Border == true)
                {
                    e.Graphics.DrawPath(new Pen(BorderColor), DrawingHelper.RoundedRect(rcBorder, iCornerRadius, Corners));
                }
            }
            else
            {
                e.Graphics.FillRectangle(brBrush, rcContent);
                if (Border == true)
                {
                    e.Graphics.DrawRectangle(new Pen(BorderColor), rcBorder);
                }
            }
            
            // Draw Text..
            if (!string.IsNullOrEmpty(this.Text))
            {
                StringFormat sf = Common.StringFormatAlignment(this.TextAlign);
                Rectangle r = new Rectangle(8, 8, this.Width - 17, this.Height - 17);
                e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), r, sf);
            }

            //Dim brShadow As New SolidBrush(Color.FromArgb(85, 0, 0, 0)) 

            //e.Graphics.DrawString("This is a title", Font, brShadow, ContentPadding.Left + 2, ContentPadding.Right + 2) 
            //e.Graphics.DrawString("This is a title", Font, Brushes.White, ContentPadding.Left, ContentPadding.Right) 

            if ((Image != null))
            {
                Bitmap btBitmap = (Bitmap)Image;
                float[][] arArray = { new float[] { 1, 0, 0, 0, 0 }, new float[] { 0, 1, 0, 0, 0 }, new float[] { 0, 0, 1, 0, 0 }, new float[] { 0, 0, 0, (float)ImageAlpha / 100, 0 }, new float[] { 0, 0, 0, 0, 1 } };

                ColorMatrix clrMatrix;
                if (Grayscale)
                {
                    clrMatrix = new ColorMatrix(new float[][] { new float[] { 0.299f, 0.299f, 0.299f, 0, 0 }, new float[] { 0.587f, 0.587f, 0.587f, 0, 0 }, new float[] { 0.114f, 0.114f, 0.114f, 0, 0 }, new float[] { 0, 0, 0, (float)ImageAlpha / 100, 0 }, new float[] { 0, 0, 0, 0, 1 } });
                }
                else
                {
                    clrMatrix = new ColorMatrix(new float[][] { new float[] { 1, 0, 0, 0, 0 }, new float[] { 0, 1, 0, 0, 0 }, new float[] { 0, 0, 1, 0, 0 }, new float[] { 0, 0, 0, (float)ImageAlpha / 100, 0 }, new float[] { 0, 0, 0, 0, 1 } });
                }

                ImageAttributes imgAttributes = new ImageAttributes();

                imgAttributes.SetColorMatrix(clrMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

                Rectangle rcImage = new Rectangle(0, 0, 10, 10);
                switch (ImagePosition)
                {
                    case ImagePosition.TopLeft:
                        rcImage = new Rectangle(ContentPadding.Left + ImagePadding.Left, ImagePadding.Top + ContentPadding.Top, ImageSize.Width, ImageSize.Height);
                        break;
                    case ImagePosition.BottomRight:
                        rcImage = new Rectangle(ContentPadding.Right + rcContent.Width - ImageSize.Width - ImagePadding.Right, ContentPadding.Top + rcContent.Height - ImageSize.Height - ImagePadding.Bottom, ImageSize.Width, ImageSize.Height);
                        break;
                    case ImagePosition.TopRight:
                        rcImage = new Rectangle(ContentPadding.Right + rcContent.Width - ImageSize.Width - ImagePadding.Right, ImagePadding.Top + ContentPadding.Top, ImageSize.Width, ImageSize.Height);
                        break;
                    case ImagePosition.BottomLeft:
                        rcImage = new Rectangle(ContentPadding.Right + ImagePadding.Left, rcContent.Height - ImageSize.Height - ImagePadding.Bottom + ContentPadding.Top, ImageSize.Width, ImageSize.Height);
                        break;
                    case ImagePosition.Center:
                        rcImage = new Rectangle(((rcContent.Width - ImageSize.Width) / 2) + ContentPadding.Left, ((rcContent.Height - ImageSize.Height) / 2) + ContentPadding.Top, ImageSize.Width, ImageSize.Height);
                        break;
                }
                e.Graphics.DrawImage(btBitmap, rcImage, 0, 0, btBitmap.Width, btBitmap.Height, GraphicsUnit.Pixel, imgAttributes);
            }
        }
    }
}
